using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;

namespace CriticalSystems.Instrumentation.Internal
{
    internal static class ReflectionHelper
    {
        private static readonly IList<string> infrastructureNamespaces = new List<string> { "CriticalSystems.Instrumentation", "CriticalSystems.Instrumentation.Internal" };

        public static MethodBase GetCallingMethod()
        {
            return GetCallingMethod(false);
        }

        public static MethodBase GetCallingMethod(bool clientCaller)
        {
            const int indexCallingMethod = 2;        // This will always be at least 2 calls deep.
            var stack = new StackTrace();
            MethodBase method = null;
            var outOfInfrastructure = false;


            //    Move up the stack trace, until we leave this class and enter the calling one.
            //    (If something weird happens and we don't leave this class just go to the top).
            for (var offSet = indexCallingMethod; offSet < stack.FrameCount; offSet++)
            {
                method = stack.GetFrame(offSet).GetMethod();
                Debug.WriteLine(method.Name);
                Debug.WriteLine(string.Format("declaring type {0}", method.DeclaringType != null ? method.DeclaringType.Name : null));
                if (outOfInfrastructure)
                {
                    break;
                }
                //if (method.DeclaringType == null)
                //{
                //    break;
                //}

                if (method.DeclaringType != null && !infrastructureNamespaces.Contains(method.DeclaringType.Namespace))
                {
                    outOfInfrastructure = true;
                    if (!clientCaller)
                    {
                        break;
                    }
                }
            }

            //    Return the method that called into this class.
            return method;
        }
    }
}
